<template>
  <div>
    <div class="exp_page">
      <div class="exp_container">
        <div class="exp_root_btn">
          <span>末尾添加：</span>
          <el-tag class="exp_btn" hit size="small" @click="appendExp(1)">与</el-tag>
          <el-tag class="exp_btn" type="success" hit size="small" @click="appendExp(2)">或</el-tag>
          <el-tag class="exp_btn" type="warning" hit size="small" @click="appendExp(3)">非</el-tag>
          <el-tag class="exp_btn" type="danger" hit size="small" @click="appendExp(4)">括号</el-tag>
          <el-button
            v-if="isChecking"
            type="primary"
            plain
            size="mini"
            disabled
            icon="el-icon-loading"
            style="width: 120px">
            检查中
          </el-button>
          <el-button v-else type="primary" plain size="mini" @click="handleCheckExp">检查</el-button>
        </div>
        <nested-draggable v-if="list.length" :model-value.sync="list"></nested-draggable>
      </div>
    </div>
  </div>
</template>

<script>
// 引入自定义组件
import NestedDraggable from './NestedDraggable.vue';
import {
  ExpAnd,
  expandExpression,
  ExpImmediateValue,
  ExpNot,
  ExpOr,
  ExpParentheses,
  ExpresionType,
  expressionFromString,
  getRadomExpId,
  stringExpression,
  valueExpression,
} from './expression';
// 引入第三方组件

const andExp = () => {
  const tmp = Object.assign({}, ExpAnd);
  tmp.id = getRadomExpId();
  return tmp;
};
const orExp = () => {
  const tmp = Object.assign({}, ExpOr);
  tmp.id = getRadomExpId();
  return tmp;
};
const notExp = () => {
  const tmp = Object.assign({}, ExpNot);
  tmp.id = getRadomExpId();
  return tmp;
};
const parentheses = () => {
  const tmp = Object.assign({}, ExpParentheses);
  tmp.id = getRadomExpId();
  return tmp;
};

export default {
  name: 'TagExpression',
  components: {
    NestedDraggable,
  },
  data() {
    return {
      list: [],
      ExpAnd: ExpAnd,
      ExpOr: ExpOr,
      ExpNot: ExpNot,
      isChecking: false,
    };
  },
  created() {},
  methods: {
    handleCheckExp() {
      if (this.isChecking) {
        return;
      }
      this.isChecking = true;
      try {
        const expStr = this.checkExp();
        if (expStr !== undefined) {
          this.$message({
            message: '逻辑表达式正确',
            type: 'success',
          });
        }
      } finally {
        this.isChecking = false;
      }
    },
    appendExp(val) {
      switch (val) {
        case 1:
          this.list.push(andExp());
          return;
        case 2:
          this.list.push(orExp());
          return;
        case 3:
          this.list.push(notExp());
          return;
        case 4:
          this.list.push(parentheses());
          return;
        default:
          break;
      }
    },
    addTagExp(val) {
      const tmp = Object.assign({}, ExpImmediateValue);
      tmp.name = val.name;
      tmp.code = val.code;
      tmp.id = getRadomExpId();
      this.list.push(tmp);
    },
    /**
     * 检查表达式是否有错
     *
     * @return {string} expression string
     */
    checkExp() {
      if (this.list.length === 0) {
        this.$message.error('逻辑表达式为空');
        return undefined;
      }
      try {
        // 检查 list, 括号里不能有括号
        const checkParentheses = x => {
          if (x.type !== ExpresionType.Parentheses) {
            return true;
          }
          if (x.children.length === 0) {
            return true;
          }
          return x.children.every(y => y.type != ExpresionType.Parentheses);
        };
        if (!this.list.every(checkParentheses)) {
          this.$message.error('括号里不能有括号');
          return undefined;
        }
        const expandExp = expandExpression(this.list);
        valueExpression(expandExp);
        const expString = stringExpression(expandExp);
        return expString;
      } catch (e) {
        console.log('----- check ---->', e);
        this.$message.error('逻辑表达式有错误');
        return undefined;
      }
    },
    getExpressionStr() {
      const expStr = this.checkExp();
      return expStr;
    },
    expressionFromStr(expStr) {
      if (!expStr) {
        return;
      }
      const expList = expressionFromString(expStr);
      return expList;
    },
    setExpressionList(expList) {
      this.list.splice(0, this.list.length);
      if (expList && expList.length > 0) {
        this.list.push(...expList);
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.exp_page {
  width: 100%;
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  gap: 30px;

  .exp_container {
    max-width: 1000px;
    padding: 20px;

    .exp_root_btn {
      display: inline-flex;
      align-items: center;
      justify-content: flex-start;
      gap: 10px;

      .exp_btn {
        cursor: pointer;
      }
    }
  }
}
</style>
